home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / tutorials / custEducation / opengl2 / demos / surfgrid.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  19.5 KB  |  700 lines

  1. /*
  2.  * surfgrid.c - simple test of polygon offset
  3.  *
  4.  * 1994 Simon Hui - Silicon Graphics Computer Systems
  5.  *
  6.  *  $Revision: 1.1 $
  7.  *
  8.  * usage:
  9.  *    surfgrid [-f] [-v]
  10.  *
  11.  * options:
  12.  *    -f    run on full screen
  13.  *
  14.  * keys:
  15.  *    p    toggle polygon offset
  16.  *    m    toggle multisampling
  17.  *      t       toggle surface drawing
  18.  *    g    toggle grid drawing
  19.  *    f    toggle smooth/flat shading
  20.  *      S       increase polygon offset factor
  21.  *      s       decrease polygon offset factor
  22.  *      B       increase polygon offset bias
  23.  *      b       decrease polygon offset bias
  24.  *    n    toggle whether to use GL evaluators or GLU nurbs
  25.  *    u    decr number of segments in U direction
  26.  *    U    incr number of segments in U direction
  27.  *    v    decr number of segments in V direction
  28.  *    V    incr number of segments in V direction
  29.  *    escape    quit
  30.  */
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include <math.h>
  35. #include <GL/gl.h>
  36. #include <GL/glx.h>
  37. #include <GL/glu.h>
  38. #include <X11/keysym.h>
  39. #include <Xm/MwmUtil.h>
  40. #include "util.h"
  41.  
  42. #define W 600
  43. #define H 600
  44.  
  45. static long winwidth = W, winheight = H;
  46. GC xgc;
  47. Display *dpy;
  48. Colormap cmap;
  49. Window window;
  50. XVisualInfo *vi;
  51. GLXContext cx;
  52. GLUnurbsObj *nobj;
  53. GLuint surflist, gridlist;
  54.  
  55. int singleBuffer = 0;
  56. int oneframe = 0;
  57. int useglunurbs = 0;
  58. int smooth = 1;
  59. int tracking = 0;
  60. int showgrid = 1;
  61. int showsurf = 1;
  62. int fullscreen = 0;
  63. int multisampling = 0;
  64. float modelmatrix[16];
  65. float scale = 0.5;
  66. float bias = 0.002;
  67. int usegments=4;
  68. int vsegments=4;
  69.  
  70. int spindx, spindy;
  71. int startx, starty;
  72. int curx, cury;
  73.  
  74. void redraw(void);
  75. void createlists(void);
  76.  
  77. float torusnurbpts[];
  78. float torusbezierpts[];
  79.  
  80. GLvoid
  81. printHelp( GLvoid )
  82. {
  83.     printf("Control keys:\n"
  84.         "p    toggle polygon offset\n"
  85.         "m    toggle multisampling\n"
  86.         "S       increase polygon offset factor\n"
  87.         "s       decrease polygon offset factor\n"
  88.         "B       increase polygon offset bias\n"
  89.         "b       decrease polygon offset bias\n"
  90.         "g    toggle grid drawing\n"
  91.         "f    toggle smooth/flat shading\n"
  92.         "n    toggle whether to use GL evaluators or GLU nurbs\n"
  93.         "u    decr number of segments in U direction\n"
  94.         "U    incr number of segments in U direction\n"
  95.         "v    decr number of segments in V direction\n"
  96.         "V    incr number of segments in V direction\n\n");
  97. }
  98.  
  99. void eventloop( void )
  100. {
  101.     XEvent event;
  102.     XButtonEvent *bev;
  103.     int x, y, size;
  104.     unsigned int w, h, bw, depth;
  105.     Window root;
  106.     
  107.     for (;;) {
  108.     if (XPending(dpy)) {
  109.         XNextEvent(dpy, &event);
  110.         bev = (XButtonEvent *) &event;
  111.         switch (event.type) {
  112.           case KeyPress:
  113.         {
  114.             char buf[100];
  115.             int rv;
  116.             KeySym ks;
  117.  
  118.             rv = XLookupString(&event.xkey, buf, sizeof(buf), &ks, 0);
  119.             switch (ks) {
  120.               case XK_n:
  121.             useglunurbs = !useglunurbs;
  122.             break;
  123.               case XK_p:
  124.                         if (glIsEnabled( GL_POLYGON_OFFSET_EXT )) {
  125.                 glDisable( GL_POLYGON_OFFSET_EXT );
  126.                 printf("disabling polygon offset\n");
  127.             } else {
  128.                 glEnable( GL_POLYGON_OFFSET_EXT );
  129.                 printf("enabling polygon offset\n");
  130.             }
  131.             break;
  132.               case XK_m:
  133.             if (multisampling) {
  134.                 if (glIsEnabled( GL_MULTISAMPLE_SGIS )) {
  135.                 glDisable( GL_MULTISAMPLE_SGIS );
  136.                 } else {
  137.                 glEnable( GL_MULTISAMPLE_SGIS );
  138.                 }
  139.             }
  140.             break;
  141.               case XK_g:
  142.                 showgrid = !showgrid;
  143.                     break;
  144.               case XK_t:
  145.                         showsurf = !showsurf;
  146.             break;
  147.               case XK_f:
  148.             smooth = !smooth;
  149.             if (smooth) {
  150.                 glShadeModel( GL_SMOOTH );
  151.             } else {
  152.                 glShadeModel( GL_FLAT );
  153.             }
  154.             break;
  155.               case XK_S:
  156.             scale += 0.1;
  157.             printf( "scale: %8.4f\n", scale);
  158.             break;
  159.               case XK_s:
  160.             scale -= 0.1;
  161.             printf( "scale: %8.4f\n", scale);
  162.             break;
  163.               case XK_B:
  164.             bias += 0.0001;
  165.             printf( "bias:  %8.4f\n", bias);
  166.             break;
  167.               case XK_b:
  168.             bias -= 0.0001;
  169.             printf( "bias:  %8.4f\n", bias);
  170.             break;
  171.               case XK_u:
  172.             usegments = (usegments < 2 ? 1 : usegments-1);
  173.             createlists();
  174.             break;
  175.               case XK_U:
  176.             usegments++;
  177.             createlists();
  178.             break;
  179.               case XK_v:
  180.             vsegments = (vsegments < 2 ? 1 : vsegments-1);
  181.             createlists();
  182.             break;
  183.               case XK_V:
  184.             vsegments++;
  185.             createlists();
  186.             break;
  187.               case XK_Escape:
  188.             exit(0);
  189.             break;
  190.             }
  191.             if (!XPending(dpy)) redraw();
  192.         }
  193.         break;
  194.           case Expose:
  195.         XGetGeometry(dpy, window, &root, &x, &y, &w, &h, &bw, &depth);
  196.         winwidth = w;
  197.         winheight = h;
  198.         size = (winwidth < winheight ? winwidth : winheight);
  199.         glViewport((winwidth-size)/2, (winheight-size)/2, size, size);
  200.         redraw();
  201.         break;
  202.           case ConfigureNotify:
  203.         winwidth = event.xconfigure.width;
  204.         winheight = event.xconfigure.height;
  205.         size = (winwidth < winheight ? winwidth : winheight);
  206.         glViewport((winwidth-size)/2, (winheight-size)/2, size, size);
  207.         redraw();
  208.         break;
  209.           case ButtonPress:
  210.         curx = startx = bev->x;
  211.         cury = starty = bev->y;
  212.         spindx = 0;
  213.         spindy = 0;
  214.         tracking = True;
  215.         break;
  216.           case ButtonRelease:
  217.         /*
  218.          * If user released the button while moving the mouse, keep
  219.          * spinning.
  220.          */
  221.         if (bev->x != curx || bev->y != cury) {
  222.             spindx = bev->x - curx;
  223.             spindy = bev->y - cury;
  224.         }
  225.         tracking = False;
  226.         break;
  227.           case MotionNotify:
  228.         if (XPending(dpy)) break;
  229.         curx = bev->x;
  230.         cury = bev->y;
  231.         if (curx != startx || cury != starty) {
  232.             redraw();
  233.             startx = curx;
  234.             starty = cury;
  235.         }
  236.         break;
  237.         }
  238.     } else {
  239.         if (!tracking && (spindx!=0 || spindy!=0)) {
  240.         redraw();
  241.         }
  242.     }
  243.     }
  244. }
  245.  
  246. void gridmaterials(void)
  247. {
  248.     static float front_mat_diffuse[] = { 1.0, 1.0, 0.4, 1.0 };
  249.     static float front_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  250.     static float back_mat_diffuse[] = { 1.0, 0.0, 0.0, 1.0 };
  251.     static float back_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  252.  
  253.     glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
  254.     glMaterialfv(GL_FRONT, GL_AMBIENT, front_mat_ambient);
  255.     glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
  256.     glMaterialfv(GL_BACK, GL_AMBIENT, back_mat_ambient);
  257. }
  258.  
  259. void surfacematerials(void)
  260. {
  261.     static float front_mat_diffuse[] = { 0.2, 0.7, 0.4, 1.0 };
  262.     static float front_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  263.     static float back_mat_diffuse[] = { 1.0, 1.0, 0.2, 1.0 };
  264.     static float back_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  265.  
  266.     glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
  267.     glMaterialfv(GL_FRONT, GL_AMBIENT, front_mat_ambient);
  268.     glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
  269.     glMaterialfv(GL_BACK, GL_AMBIENT, back_mat_ambient);
  270. }
  271.  
  272. void init(void)
  273. {
  274.     int i;
  275.     static float ambient[] = { 0.0, 0.0, 0.0, 1.0 };
  276.     static float diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
  277.     static float position[] = { 90.0, 90.0, 150.0, 0.0 };
  278.     static float lmodel_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
  279.     static float lmodel_twoside[] = { GL_TRUE };
  280.  
  281.     glMatrixMode(GL_PROJECTION);
  282.     glLoadIdentity();
  283.     gluPerspective( 40.0, 1.0, 2.0, 200.0 );
  284.     glMatrixMode(GL_MODELVIEW);
  285.     glLoadIdentity();
  286.     glGetFloatv(GL_MODELVIEW_MATRIX, modelmatrix);
  287.  
  288.     glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  289.     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  290.     glLightfv(GL_LIGHT0, GL_POSITION, position);
  291.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  292.  
  293.     glEnable(GL_LIGHTING);
  294.     glEnable(GL_LIGHT0);
  295.     glEnable(GL_DEPTH_TEST);
  296.     glEnable(GL_AUTO_NORMAL);
  297.     glEnable(GL_POLYGON_OFFSET_EXT);
  298.  
  299.     glEnable( GL_MAP2_VERTEX_4 );
  300.     glClearColor(0.25, 0.25, 0.5, 0.0);
  301.  
  302.     glPolygonOffsetEXT( scale, bias );
  303.  
  304.     nobj = gluNewNurbsRenderer();
  305.     gluNurbsProperty(nobj, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE );
  306.  
  307.     surflist = glGenLists(1);
  308.     gridlist = glGenLists(1);
  309.     createlists();
  310. }
  311.  
  312. void drawmesh(void)
  313. {
  314.     int i, j;
  315.     float *p;
  316.  
  317.     int up2p = 4;
  318.     int uorder = 3, vorder = 3;
  319.     int nu = 4, nv = 4;
  320.     int vp2p = up2p * uorder * nu;
  321.  
  322.     for (j=0; j < nv; j++) {
  323.     for (i=0; i < nu; i++) {
  324.         p = torusbezierpts + (j * vp2p * vorder) + (i * up2p * uorder);
  325.         glPolygonOffsetEXT( scale, bias );
  326.         glMap2f( GL_MAP2_VERTEX_4, 0.0, 1.0, up2p, 3, 0.0, 1.0, vp2p, 3,
  327.              (void*)p );
  328.         if (showsurf) {
  329.         surfacematerials();
  330.         glEvalMesh2( GL_FILL, 0, usegments, 0, vsegments );
  331.         }
  332.         if (showgrid) {
  333.                 gridmaterials();
  334.             glEvalMesh2( GL_LINE, 0, usegments, 0, vsegments );
  335.             }
  336.     }
  337.     }
  338. }
  339.  
  340. void redraw(void)
  341. {
  342.     static int i=0;
  343.     int dx, dy;
  344.     float v[3], n[3], rot[3];
  345.     float len, rlen, ang;
  346.     static GLuint vcount;
  347.  
  348.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  349.     glColor3f( 1, 0, 0);
  350.  
  351.     if (tracking) {
  352.     dx = curx - startx;
  353.     dy = cury - starty;
  354.     } else {
  355.     dx = spindx;
  356.     dy = spindy;
  357.     }
  358.     if (dx || dy) {
  359.     dy = -dy;
  360.     v[0] = dx;
  361.     v[1] = dy;
  362.     v[2] = 0;
  363.  
  364.     len = length(v);
  365.     ang = -len / 600 * 360;
  366.     norm( v );
  367.     cross( v, z_axis, rot );
  368.  
  369.     /*
  370.     ** This is certainly not recommended for programs that care
  371.     ** about performance or numerical stability: we concatenate
  372.     ** the rotation onto the current modelview matrix and read the
  373.     ** matrix back, thus saving ourselves from writing our own
  374.     ** matrix manipulation routines.
  375.     */
  376.     glLoadIdentity();
  377.     glRotatef(ang, rot[0], rot[1], rot[2]);
  378.     glMultMatrixf(modelmatrix);
  379.     glGetFloatv(GL_MODELVIEW_MATRIX, modelmatrix);
  380.     }
  381.     glLoadIdentity();
  382.     glTranslatef( 0.0, 0.0, -10.0 );
  383.     glMultMatrixf(modelmatrix);
  384.     
  385.     if (useglunurbs) {
  386.     if (showsurf) glCallList(surflist);
  387.     if (showgrid) glCallList(gridlist);
  388.     } else {
  389.     glMapGrid2f( usegments, 0.0, 1.0, vsegments, 0.0, 1.0 );
  390.     drawmesh();
  391.     }
  392.     if (singleBuffer) glFlush();
  393.     else glXSwapBuffers(dpy, window);
  394. }
  395.  
  396. static int attributes[] = {
  397.     GLX_SAMPLES_SGIS, 4,
  398.     GLX_RGBA,
  399.     GLX_RED_SIZE, 1,
  400.     GLX_GREEN_SIZE, 1,
  401.     GLX_BLUE_SIZE, 1,
  402.     GLX_DEPTH_SIZE, 1,
  403.     GLX_DOUBLEBUFFER,        /* must be last */
  404.     None,
  405. };
  406.  
  407. static void usage(void)
  408. {
  409.     printf("usage: surfgrid [-f]\n");
  410.     exit(-1);
  411. }
  412.  
  413. Window createwindow( int defW, int defH, int defX, int defY,
  414.              int attributes[], int argc, char **argv,
  415.              Bool fullscreen );
  416.  
  417. /*
  418.  *  pass the name of the desired extension.
  419.  *  this will return 1 if the extension is supported, 0 otherwise.
  420.  */
  421. int
  422. getextension(char *e)
  423. {
  424. const GLubyte *s;
  425.  
  426.     s = glGetString(GL_EXTENSIONS);
  427.     if (!s)
  428.     return 0;
  429.     if (*s == '\0')
  430.      return 0;
  431.     return (strstr(s,e) == 0) ? 0 : 1;
  432. }
  433.  
  434. int main(int argc, char **argv)
  435. {
  436.     int i, n, ms;
  437.  
  438.     for (i=1; i<argc; i++) {
  439.     if (argv[i][0] == '-') {
  440.         switch (argv[i][1]) {
  441.           case 's':
  442.         if (!strcmp(argv[i],"-sb")) {
  443.             attributes[11] = None;
  444.             singleBuffer = 1;
  445.         } else {
  446.             usage();
  447.         }
  448.         break;
  449.           case 'f':
  450.         fullscreen = 1;
  451.         break;
  452.           case 'g':
  453.         showgrid = 0;
  454.         break;
  455.           case 't':
  456.         showsurf = 0;
  457.         break;
  458.           case 'u':
  459.         if (i > argc-1) usage();
  460.         usegments = vsegments = atoi(argv[i+1]);
  461.         i++;
  462.         break;
  463.           case 'v':
  464.         if (i > argc-1) usage();
  465.         vsegments = atoi(argv[i+1]);
  466.         i++;
  467.         break;
  468.           case '1':
  469.         oneframe = 1;
  470.         break;
  471.           default:
  472.         usage();
  473.         break;
  474.         }
  475.     } else {
  476.         usage();
  477.     }
  478.     }
  479.  
  480.     window = createwindow( winwidth, winheight, 50, 50, attributes,
  481.                argc, argv, fullscreen );
  482.     cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
  483.     if (!glXMakeCurrent(dpy, window, cx)) {
  484.     fprintf(stderr, "Can't make window current to context\n");
  485.     return -1;
  486.     }
  487.     if (!getextension("GL_EXT_polygon_offset")) {
  488.     printf("Warning: GL_EXT_polygon_offset not supported on this machine.. trying anyway\n");
  489.     }
  490.     init();
  491.     printHelp();
  492.     if (oneframe) {
  493.     char buf[10];
  494.     redraw();
  495.     gets(buf);
  496.     exit(1);
  497.     }
  498.     eventloop();
  499.     glXMakeCurrent(dpy, None, NULL);
  500.     glXDestroyContext(dpy, cx);
  501.     XCloseDisplay(dpy);
  502. }
  503.  
  504. /****************************************************************************/
  505.  
  506. float circleknots[] = { 0.0, 0.0, 0.0, 0.25, 0.50, 0.50, 0.75, 1.0, 1.0, 1.0 };
  507.  
  508. void createlists(void)
  509. {
  510.     gluNurbsProperty(nobj, GLU_U_STEP, (usegments-1)*4 );
  511.     gluNurbsProperty(nobj, GLU_V_STEP, (vsegments-1)*4 );
  512.  
  513.     gluNurbsProperty(nobj, GLU_DISPLAY_MODE, GLU_FILL);
  514.     glNewList(surflist, GL_COMPILE);
  515.         surfacematerials();
  516.         gluBeginSurface(nobj);
  517.         gluNurbsSurface(nobj, 10, circleknots, 10, circleknots,
  518.                 4, 28, torusnurbpts, 3, 3, GL_MAP2_VERTEX_4);
  519.         gluEndSurface(nobj);
  520.     glEndList();
  521.  
  522.     gluNurbsProperty(nobj, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
  523.     glNewList(gridlist, GL_COMPILE);
  524.         gridmaterials();
  525.         gluBeginSurface(nobj);
  526.         gluNurbsSurface(nobj, 10, circleknots, 10, circleknots,
  527.                 4, 28, torusnurbpts, 3, 3, GL_MAP2_VERTEX_4);
  528.         gluEndSurface(nobj);
  529.     glEndList();
  530. }
  531.  
  532. /****************************************************************************/
  533.  
  534. /*
  535.  * Create an X window.
  536.  */
  537.  
  538. static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
  539. {
  540.     if ((e->type == MapNotify) && (e->xmap.window == (Window)arg)) {
  541.     return GL_TRUE;
  542.     }
  543.     return GL_FALSE;
  544. }
  545.  
  546. Window createwindow(int w, int h, int x, int y, int attributes[],
  547.             int argc, char **argv, Bool fullscreen)
  548. {
  549.     Window window;
  550.     XSetWindowAttributes swa;
  551.     unsigned int width, height;
  552.     XSizeHints sh;
  553.     XEvent event;
  554.     char buf[20];
  555.  
  556.     dpy = XOpenDisplay(0);
  557.     if (!dpy) {
  558.     fprintf(stderr, "Can't connect to display \"%s\"\n",
  559.         getenv("DISPLAY"));
  560.     exit(1);
  561.     }
  562.     /* tries for a multisample visual first, cause it looks a lot nicer */
  563.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
  564.     if (vi) {
  565.     multisampling = 1;
  566.     } else {
  567.     /* try for a non-multisample visual */
  568.     vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attributes[2]);
  569.     if (!vi) {
  570.         fprintf(stderr, "Cannot find visual on \"%s\"\n",
  571.             getenv("DISPLAY"));
  572.         exit(1);
  573.     }
  574.     }
  575.  
  576.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual,
  577.                AllocNone);
  578.     swa.background_pixel = 0;
  579.     swa.border_pixel = 0;
  580.     swa.colormap = cmap;
  581.     swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask
  582.       | KeyReleaseMask | ButtonPressMask | ButtonMotionMask
  583.     | ButtonReleaseMask;
  584.  
  585.     if (fullscreen) {
  586.     width = DisplayWidth( dpy, 0 );
  587.     height = DisplayHeight( dpy, 0 );
  588.     sh.x = 0;
  589.     sh.y = 0;
  590.     sprintf( buf, "%dx%d+0+0", DisplayWidth(dpy,0), DisplayHeight(dpy,0));
  591.     } else {
  592.     width = w;
  593.     height = h;
  594.     sh.x = x;
  595.     sh.y = y;
  596.     }
  597.     sh.flags = USPosition | PPosition;
  598.     window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), sh.x, sh.y,
  599.                width, height,
  600.                0, vi->depth, InputOutput, vi->visual,
  601.                CWBorderPixel|CWColormap|CWEventMask|CWBackPixel,
  602.                &swa);
  603.     XSetStandardProperties(dpy, window, argv[0], argv[0],
  604.                None, argv, argc, &sh);
  605.     XSetWMColormapWindows(dpy, window, &window, 1);
  606.     if (fullscreen) {
  607.     /* turn off window decorations */
  608.     Atom hints_atom;
  609.     MotifWmHints hints;
  610.  
  611.     hints_atom = XInternAtom( dpy, "_MOTIF_WM_HINTS", 0 );
  612.     hints.flags = MWM_HINTS_DECORATIONS;
  613.     hints.decorations = 0;
  614.     XChangeProperty( dpy, window, hints_atom, hints_atom, 32,
  615.              PropModeReplace, (unsigned char*)&hints, 5 );
  616.     }
  617.     XMapWindow(dpy, window);
  618.     XIfEvent(dpy, &event, WaitForMapNotify, (char*)window);
  619.     return window;
  620. }
  621.  
  622. /*
  623.  * Control points of the torus in Bezier form.  Can be rendered
  624.  * using OpenGL evaluators.
  625.  */
  626. static GLfloat torusbezierpts[] = {
  627.          4.0, 0.0, 0.0, 4.0,  2.0, 0.0, 1.0, 2.0,  3.0, 0.0, 1.0, 2.0, 
  628.          3.0, 0.0, 1.0, 2.0,  4.0, 0.0, 1.0, 2.0,  8.0, 0.0, 0.0, 4.0, 
  629.          8.0, 0.0, 0.0, 4.0,  4.0, 0.0,-1.0, 2.0,  3.0, 0.0,-1.0, 2.0, 
  630.          3.0, 0.0,-1.0, 2.0,  2.0, 0.0,-1.0, 2.0,  4.0, 0.0, 0.0, 4.0, 
  631.          2.0, 2.0, 0.0, 2.0,  1.0, 1.0, 0.5, 1.0,  1.5, 1.5, 0.5, 1.0, 
  632.          1.5, 1.5, 0.5, 1.0,  2.0, 2.0, 0.5, 1.0,  4.0, 4.0, 0.0, 2.0, 
  633.          4.0, 4.0, 0.0, 2.0,  2.0, 2.0,-0.5, 1.0,  1.5, 1.5,-0.5, 1.0, 
  634.          1.5, 1.5,-0.5, 1.0,  1.0, 1.0,-0.5, 1.0,  2.0, 2.0, 0.0, 2.0, 
  635.          0.0, 2.0, 0.0, 2.0,  0.0, 1.0, 0.5, 1.0,  0.0, 1.5, 0.5, 1.0, 
  636.          0.0, 1.5, 0.5, 1.0,  0.0, 2.0, 0.5, 1.0,  0.0, 4.0, 0.0, 2.0, 
  637.          0.0, 4.0, 0.0, 2.0,  0.0, 2.0,-0.5, 1.0,  0.0, 1.5,-0.5, 1.0, 
  638.          0.0, 1.5,-0.5, 1.0,  0.0, 1.0,-0.5, 1.0,  0.0, 2.0, 0.0, 2.0, 
  639.          0.0, 2.0, 0.0, 2.0,  0.0, 1.0, 0.5, 1.0,  0.0, 1.5, 0.5, 1.0, 
  640.          0.0, 1.5, 0.5, 1.0,  0.0, 2.0, 0.5, 1.0,  0.0, 4.0, 0.0, 2.0, 
  641.          0.0, 4.0, 0.0, 2.0,  0.0, 2.0,-0.5, 1.0,  0.0, 1.5,-0.5, 1.0, 
  642.          0.0, 1.5,-0.5, 1.0,  0.0, 1.0,-0.5, 1.0,  0.0, 2.0, 0.0, 2.0, 
  643.         -2.0, 2.0, 0.0, 2.0, -1.0, 1.0, 0.5, 1.0, -1.5, 1.5, 0.5, 1.0, 
  644.         -1.5, 1.5, 0.5, 1.0, -2.0, 2.0, 0.5, 1.0, -4.0, 4.0, 0.0, 2.0, 
  645.         -4.0, 4.0, 0.0, 2.0, -2.0, 2.0,-0.5, 1.0, -1.5, 1.5,-0.5, 1.0, 
  646.         -1.5, 1.5,-0.5, 1.0, -1.0, 1.0,-0.5, 1.0, -2.0, 2.0, 0.0, 2.0, 
  647.         -4.0, 0.0, 0.0, 4.0, -2.0, 0.0, 1.0, 2.0, -3.0, 0.0, 1.0, 2.0, 
  648.         -3.0, 0.0, 1.0, 2.0, -4.0, 0.0, 1.0, 2.0, -8.0, 0.0, 0.0, 4.0, 
  649.         -8.0, 0.0, 0.0, 4.0, -4.0, 0.0,-1.0, 2.0, -3.0, 0.0,-1.0, 2.0, 
  650.         -3.0, 0.0,-1.0, 2.0, -2.0, 0.0,-1.0, 2.0, -4.0, 0.0, 0.0, 4.0, 
  651.         -4.0, 0.0, 0.0, 4.0, -2.0, 0.0, 1.0, 2.0, -3.0, 0.0, 1.0, 2.0, 
  652.         -3.0, 0.0, 1.0, 2.0, -4.0, 0.0, 1.0, 2.0, -8.0, 0.0, 0.0, 4.0, 
  653.         -8.0, 0.0, 0.0, 4.0, -4.0, 0.0,-1.0, 2.0, -3.0, 0.0,-1.0, 2.0, 
  654.         -3.0, 0.0,-1.0, 2.0, -2.0, 0.0,-1.0, 2.0, -4.0, 0.0, 0.0, 4.0, 
  655.         -2.0,-2.0, 0.0, 2.0, -1.0,-1.0, 0.5, 1.0, -1.5,-1.5, 0.5, 1.0, 
  656.         -1.5,-1.5, 0.5, 1.0, -2.0,-2.0, 0.5, 1.0, -4.0,-4.0, 0.0, 2.0, 
  657.         -4.0,-4.0, 0.0, 2.0, -2.0,-2.0,-0.5, 1.0, -1.5,-1.5,-0.5, 1.0, 
  658.         -1.5,-1.5,-0.5, 1.0, -1.0,-1.0,-0.5, 1.0, -2.0,-2.0, 0.0, 2.0, 
  659.          0.0,-2.0, 0.0, 2.0,  0.0,-1.0, 0.5, 1.0,  0.0,-1.5, 0.5, 1.0, 
  660.          0.0,-1.5, 0.5, 1.0,  0.0,-2.0, 0.5, 1.0,  0.0,-4.0, 0.0, 2.0, 
  661.          0.0,-4.0, 0.0, 2.0,  0.0,-2.0,-0.5, 1.0,  0.0,-1.5,-0.5, 1.0, 
  662.          0.0,-1.5,-0.5, 1.0,  0.0,-1.0,-0.5, 1.0,  0.0,-2.0, 0.0, 2.0, 
  663.          0.0,-2.0, 0.0, 2.0,  0.0,-1.0, 0.5, 1.0,  0.0,-1.5, 0.5, 1.0, 
  664.          0.0,-1.5, 0.5, 1.0,  0.0,-2.0, 0.5, 1.0,  0.0,-4.0, 0.0, 2.0, 
  665.          0.0,-4.0, 0.0, 2.0,  0.0,-2.0,-0.5, 1.0,  0.0,-1.5,-0.5, 1.0, 
  666.          0.0,-1.5,-0.5, 1.0,  0.0,-1.0,-0.5, 1.0,  0.0,-2.0, 0.0, 2.0, 
  667.          2.0,-2.0, 0.0, 2.0,  1.0,-1.0, 0.5, 1.0,  1.5,-1.5, 0.5, 1.0, 
  668.          1.5,-1.5, 0.5, 1.0,  2.0,-2.0, 0.5, 1.0,  4.0,-4.0, 0.0, 2.0, 
  669.          4.0,-4.0, 0.0, 2.0,  2.0,-2.0,-0.5, 1.0,  1.5,-1.5,-0.5, 1.0, 
  670.          1.5,-1.5,-0.5, 1.0,  1.0,-1.0,-0.5, 1.0,  2.0,-2.0, 0.0, 2.0, 
  671.          4.0, 0.0, 0.0, 4.0,  2.0, 0.0, 1.0, 2.0,  3.0, 0.0, 1.0, 2.0, 
  672.          3.0, 0.0, 1.0, 2.0,  4.0, 0.0, 1.0, 2.0,  8.0, 0.0, 0.0, 4.0, 
  673.          8.0, 0.0, 0.0, 4.0,  4.0, 0.0,-1.0, 2.0,  3.0, 0.0,-1.0, 2.0, 
  674.          3.0, 0.0,-1.0, 2.0,  2.0, 0.0,-1.0, 2.0,  4.0, 0.0, 0.0, 4.0, 
  675. };
  676.  
  677. /*
  678.  * Control points of a torus in NURBS form.  Can be rendered using
  679.  * the GLU NURBS routines.
  680.  */
  681. static GLfloat torusnurbpts[] = {
  682.          4.0, 0.0, 0.0, 4.0,  2.0, 0.0, 1.0, 2.0,  4.0, 0.0, 1.0, 2.0, 
  683.          8.0, 0.0, 0.0, 4.0,  4.0, 0.0,-1.0, 2.0,  2.0, 0.0,-1.0, 2.0, 
  684.          4.0, 0.0, 0.0, 4.0,  2.0, 2.0, 0.0, 2.0,  1.0, 1.0, 0.5, 1.0, 
  685.          2.0, 2.0, 0.5, 1.0,  4.0, 4.0, 0.0, 2.0,  2.0, 2.0,-0.5, 1.0, 
  686.          1.0, 1.0,-0.5, 1.0,  2.0, 2.0, 0.0, 2.0, -2.0, 2.0, 0.0, 2.0, 
  687.         -1.0, 1.0, 0.5, 1.0, -2.0, 2.0, 0.5, 1.0, -4.0, 4.0, 0.0, 2.0, 
  688.         -2.0, 2.0,-0.5, 1.0, -1.0, 1.0,-0.5, 1.0, -2.0, 2.0, 0.0, 2.0, 
  689.         -4.0, 0.0, 0.0, 4.0, -2.0, 0.0, 1.0, 2.0, -4.0, 0.0, 1.0, 2.0, 
  690.         -8.0, 0.0, 0.0, 4.0, -4.0, 0.0,-1.0, 2.0, -2.0, 0.0,-1.0, 2.0, 
  691.         -4.0, 0.0, 0.0, 4.0, -2.0,-2.0, 0.0, 2.0, -1.0,-1.0, 0.5, 1.0, 
  692.         -2.0,-2.0, 0.5, 1.0, -4.0,-4.0, 0.0, 2.0, -2.0,-2.0,-0.5, 1.0, 
  693.         -1.0,-1.0,-0.5, 1.0, -2.0,-2.0, 0.0, 2.0,  2.0,-2.0, 0.0, 2.0, 
  694.          1.0,-1.0, 0.5, 1.0,  2.0,-2.0, 0.5, 1.0,  4.0,-4.0, 0.0, 2.0, 
  695.          2.0,-2.0,-0.5, 1.0,  1.0,-1.0,-0.5, 1.0,  2.0,-2.0, 0.0, 2.0, 
  696.          4.0, 0.0, 0.0, 4.0,  2.0, 0.0, 1.0, 2.0,  4.0, 0.0, 1.0, 2.0, 
  697.          8.0, 0.0, 0.0, 4.0,  4.0, 0.0,-1.0, 2.0,  2.0, 0.0,-1.0, 2.0, 
  698.          4.0, 0.0, 0.0, 4.0, 
  699. };
  700.